﻿/***************************************************************
TODO
-PetsAlive EnemyPetsAlive
***************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;

using Styx;
using Styx.Common;
using Styx.Common.Helpers;
using Styx.CommonBot;
using Styx.Helpers;
using Styx.Pathing;
using Styx.Plugins;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;


namespace BattleBuddyplug
{
    public static class BBLog
    {
        public enum LogType
        {
            LOG_ERROR=1,
            LOG_WARN=2,
            LOG_MESSAGE=4,
            LOG_ALWAYS=8,
            LOG_TRACE=16
        };

        static int LogLevel = (int) LogType.LOG_WARN | (int) LogType.LOG_ERROR;

        static BBLog()
        {
        }

        public static void Log(string msg)
        {
            Log(LogType.LOG_MESSAGE, msg);
        }

        public static void Log(LogType level, string msg)
        {
            //int effectiveLogLevel = LogLevel;
            //if (BattleBuddy._MySettings.DetailedLogging) {
            //    effectiveLogLevel |= ((int)LogType.LOG_MESSAGE | (int)LogType.LOG_TRACE);
            //}

            if ((level==LogType.LOG_ALWAYS) || (((int) level & LogLevel) != 0))
            {
                System.Windows.Media.Color logcolor = System.Windows.Media.Colors.LightCyan;
                switch (level) {
                    case LogType.LOG_ERROR: logcolor = System.Windows.Media.Colors.Pink; break;
                    case LogType.LOG_WARN: logcolor = System.Windows.Media.Colors.Yellow; break;
                }
                Logging.Write("[BB] " + msg);
            } else {
                //Logging.WriteQuiet("[BB] " + msg);
                Logging.WriteToFileSync(Styx.Common.LogLevel.Diagnostic, "[BB] " + msg);
            }
        }

        public static void LogError(string msg)
        {
            Log(LogType.LOG_ERROR, msg);
        }

        public static void LogWarning(string msg)
        {
            Log(LogType.LOG_WARN, msg);
        }

        public static void LogTrace(string msg)
        {
            Log(LogType.LOG_TRACE, msg);
        }

        public static void LogAlways(string msg)
        {
            Log(LogType.LOG_ALWAYS, msg);
        }

        public static void LogException(Exception ex)
        {
            Log(LogType.LOG_ERROR, "ERROR: Caught Exception");
            Logging.WriteException(ex);
            Logging.Write(System.Windows.Media.Colors.Yellow, ex.Message);
            Logging.Write(System.Windows.Media.Colors.Yellow, ex.StackTrace);
        }
    }


    public partial class BattleBuddy : HBPlugin
    {
        public static System.Windows.Media.Color logColor = System.Windows.Media.Colors.Pink;
        private readonly WaitTimer _updateTimer = WaitTimer.TenSeconds;
        private ulong _OldGuid = 0;
        private int _SkipCounter = 0;
        private bool _InitDone = false;
        private int _BlacklistCounter = 0;
        private bool _DidError = false;
        private WoWPoint _OldLocation = new WoWPoint(0, 0, 0);
        private configForm _ConfigForm = new configForm();
        private static Stopwatch _Timer = new Stopwatch();
        private Stopwatch _SwapTimer = new Stopwatch();
        private Stopwatch _HealTimer = new Stopwatch();
        private Stopwatch _StuckTimer = new Stopwatch();
        private Stopwatch _LogicTimer = new Stopwatch();
        private Stopwatch _InteractTimer = new Stopwatch();
        private Stopwatch _MoveTimer = new Stopwatch();
        private static int _BattleRoundNumber;
        private static bool _AttachedLua = false;
        private static int[] _FixedIndex;
        private bool _RingerMode = true;

        private string[] _PetDefaultLogics = { 
            "SWAPOUT Health(THISPET) ISLESSTHAN 30",
            "PASSTURN HASBUFF(822) EQUALS true",
            "PASSTURN HASBUFF(498) EQUALS true",
            "CASTSPELL(1) COOLDOWN(SKILL(1)) EQUALS false"
        };

        public static BBSettings _MySettings;
        public int _PvpTimer;
        public bool _Disabled = false;
        public bool _PriorFramelock;
        public string _TempOrder = "";
        public static PetBattleSettings _PetSettings;
        public static PetBattleSettings _DefaultLogicz;

        public static string _BattleBuddyPath;
        public static string _PetLogicsDbPath;
        public static string _WhitelistPath;
        public static string _BlacklistPath;
        public static string _LogicMacroPath;
        public static string _DefaultLogicPath;
        public static string _PetSettingsPath;
        public static string _QuickSettingsPath;

        public static List<string> _TheBlacklist = new List<string>();
        public static List<string> _TheWhitelist = new List<string>();
        public static List<string> _QuickSettingsNames = new List<string>();
        public static List<string> _QuickSettingsDescriptions = new List<string>();
        public static List<string> _QuickSettingsFunctions = new List<string>();
        
        public BattleBuddy()
        {
            // All initialization in Init routine
        }

        internal static void StatCounter()
        {
            if (_MySettings.CheckAllowUsageTracking) {
                try {
                    var statcounterDate = DateTime.Now.DayOfYear.ToString(System.Globalization.CultureInfo.InvariantCulture);

                    if (_MySettings.LastDayChecked != statcounterDate) {
                        new MemoryStream(new WebClient().DownloadData("http://c.statcounter.com/9192897/0/964adce3/1/"));
                        _MySettings.LastDayChecked = statcounterDate;
                        _MySettings.Save();
                    }
                } catch { } // Catch all, like 404's.
            }
        }

        private void AttachLuaEvents()
        {
            if (_AttachedLua) return;
            BBLog.LogTrace("Lua events attached");
            _AttachedLua = true;
            Lua.Events.AttachEvent("PET_BATTLE_CLOSE", LuaEndOfBattle);
            //Lua.Events.AttachEvent("PET_BATTLE_OPENING_START", LuaPetBattleStarted);
            //Lua.Events.AttachEvent("PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE", LuaEndOfRound);
            //Lua.Events.AttachEvent("PET_BATTLE_TURN_STARTED", LuaRoundStart);
            //Lua.Events.AttachEvent("CHAT_MSG_PET_BATTLE_COMBAT_LOG", PetChatter);
        }

        private void DetachLuaEvents()
        {
            if (!_AttachedLua) return;
            _AttachedLua = false;
            Lua.Events.DetachEvent("PET_BATTLE_CLOSE", LuaEndOfBattle);
            //Lua.Events.DetachEvent("PET_BATTLE_OPENING_START", LuaPetBattleStarted);
            //Lua.Events.DetachEvent("PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE", LuaEndOfRound);
            //Lua.Events.DetachEvent("PET_BATTLE_TURN_STARTED", LuaRoundStart);
            //Lua.Events.DetachEvent("CHAT_MSG_PET_BATTLE_COMBAT_LOG", PetChatter);
        }

        // LUA Event handler
        private void PetChatter(object sender, LuaEventArgs args)
        {
            BBLog.LogTrace(sender.ToString() + " " + args.Args[0]);
        }

        // LUA Event handler
        private void LuaEndOfBattle(object sender, LuaEventArgs args)
        {
            BBLog.LogAlways("Battle Finished");
        }

        // LUA Event handler
        private void LuaPetBattleStarted(object sender, LuaEventArgs args)
        {
        }

        // LUA Event handler
        private void LuaEndOfRound(object sender, LuaEventArgs args)
        {
        }

        // LUA Event handler
        private void LuaRoundStart(object sender, LuaEventArgs args)
        {
        }


        public string ValidateFile(string fname)
        {
            string filename = Path.Combine(_BattleBuddyPath, fname);
            string reserve = Path.Combine(_BattleBuddyPath, "Data", fname) + ".default";
            if (!File.Exists(filename)) File.Copy(reserve, filename);
            return filename;
        }

        public void CreateFilesIfNeeded()
        {
            _PetLogicsDbPath = ValidateFile("PetLogics.db");
            _WhitelistPath = ValidateFile("whitelist.txt");
            _BlacklistPath = ValidateFile("blacklist.txt");
            _LogicMacroPath = ValidateFile("logicmacro.txt");
            _DefaultLogicPath = ValidateFile("Default Logic.xml");
        }


        public override void Initialize()
        {
            if (_InitDone) return;
            _InitDone = true;

            _BattleBuddyPath = Path.Combine(Application.StartupPath, "Plugins", Name);
            BBLog.Log("BuddyBattlePath:" + _BattleBuddyPath);
            _PetSettingsPath = Path.Combine(_BattleBuddyPath, "PetSettings");
            _QuickSettingsPath = Path.Combine(_BattleBuddyPath, "QuickSettings");
            try {
                _MySettings = new BBSettings(Path.Combine(Settings.CharacterSettingsDirectory, "BattleBuddy.xml"));
                CreateFilesIfNeeded();
                LoadDefaultLogic();
                BlacklistLoad();
                WhitelistLoad();
            } catch (Exception ex) { BBLog.LogException(ex); }

            if (_MySettings.AdFormula.Contains("DisFactor")) {
                _MySettings.HPFormula = "petHP * HPFactor";
                _MySettings.AdFormula = "advantage * 50 * AdFactor";
                _MySettings.DisFormula = "disadvantage * 50 * DisFactor";
                _MySettings.LevelFormula = "(petLevel - enemylevel) * 4 * LevelFactor";
            }

            _Timer.Reset();
            _Timer.Start();

            _BattleRoundNumber = 0;
            _FixedIndex = new int[] { 0, 1, 2, 3 };

            PrintSettings();

            LoadPetSettings("0", "0");

            Updater.CheckForUpdate(_BattleBuddyPath);
            AttachLuaEvents();
        }

        public override void OnButtonPress()
        {
            _ConfigForm.Close();
            _ConfigForm = new configForm();
            _ConfigForm.Show();
        }

        private void Nothing(object sender, EventArgs a, CancelEventArgs e)
        {
            if (InPetCombat()) e.Cancel = true;
        }

        // A pet is a puppy if it's level is less than 85% of it's enemy
        //   Note: if there are two pets lower than the enemy, and the older pet is dead, still returns true.
        private bool IsThisAPuppy()
        {
            int PuppyGap = (GetCurrentPetLevel() * 100 / GetCurrentEnemyLevel());
            if  (   (PuppyGap <= 85)
                &&  (   GetPetLevel(1) >= GetCurrentEnemyLevel() 
                    ||  GetPetLevel(2) >= GetCurrentEnemyLevel() 
                    ||  GetPetLevel(3) >= GetCurrentEnemyLevel()
                    )
                && (GetPetsAlive() >= 2)
                ) {
                BBLog.Log("Using puppy logic.");
                return true;
            }
            return false;
        }


        private void FixIndexes()
        {
            _FixedIndex = new int[] { 0, 1, 2, 3, 0, 0, 0 };

            if (GetPetHPPreCombat(2) == 0) {
                _FixedIndex = ArrayRemoveAt(_FixedIndex, 2);
            }

            if (GetPetHPPreCombat(1) == 0) {
                _FixedIndex = ArrayRemoveAt(_FixedIndex, 1);
            }
        }

        private int[] ArrayRemoveAt(int[] source, int index)
        {
            int[] dest = new int[source.Length - 1];
            if (index > 0)
                Array.Copy(source, 0, dest, 0, index);

            if (index < source.Length - 1)
                Array.Copy(source, index + 1, dest, index, source.Length - index - 1);

            return dest;
        }

        public override void Pulse()
        {
            if (_Disabled) return;
            if (StyxWoW.Me.Combat) return;

            if (!_DidError && GlobalSettings.Instance.UseFrameLock) {
                _DidError = true;
            }

            if (!_SwapTimer.IsRunning) _SwapTimer.Start();
            if (!_HealTimer.IsRunning) _HealTimer.Start();
            if (!_StuckTimer.IsRunning) _StuckTimer.Start();
            if (!_LogicTimer.IsRunning) _LogicTimer.Start();
            if (!_InteractTimer.IsRunning) _InteractTimer.Start();
            if (!_MoveTimer.IsRunning) _MoveTimer.Start();
            if (!InPetCombat()) {
                UpdatePetSlot();
                FixIndexes();
            }


            StatCounter();

            if (!MinimumRequirementsMet()) {
                _Disabled = true;
                return;
            }

            if (_MySettings.BPSEnabled) {
                //    BBLog("Pulsing BPS");
                try {
                    //        BPS.Pulse();
                } catch (Exception e) {
                    BBLog.LogException(e);
                }
            }

            if (Styx.StyxWoW.Me.IsAlive && !Styx.StyxWoW.Me.Combat) {
                if (!InPetCombat()) _TempOrder = "";
                if (BattleBuddy._MySettings.DoPVP && !InPetCombat()) {
                    //check for pvp queue
                    List<string> cnt = Lua.GetReturnValues("if C_PetBattles.GetPVPMatchmakingInfo()=='queued' then return true end return false");

                    //niet queued? Moet ik queuen?
                    if (cnt[0] == "0") {
                        Lua.DoString("if C_PetBattles.GetPVPMatchmakingInfo()=='proposal' then C_PetBattles.AcceptQueuedPVPMatch() end");

                        //BBLog.Log("Queue after"+pvptimer+ "now at"+timer.ElapsedMilliseconds/600);
                        if (_PvpTimer < 1) {
                            Random _ran = new Random();
                            //BBLog.Log("Queue"+(BattleBuddy.MySettings.PVPMaxTime+1)*100);
                            _PvpTimer = _ran.Next((BattleBuddy._MySettings.PVPMinTime + 1) * 100, ((BattleBuddy._MySettings.PVPMinTime + 1) + BattleBuddy._MySettings.PVPMaxTime + 1) * 100);
                            BBLog.LogTrace("new timer set" + _PvpTimer.ToString() + "  " + BattleBuddy._MySettings.PVPMinTime + "  " + 100 * (BattleBuddy._MySettings.PVPMinTime + 1 + BattleBuddy._MySettings.PVPMaxTime + 1));
                        }

                        if (_Timer.ElapsedMilliseconds > _PvpTimer * 600 && _PvpTimer != 0) {
                            //BBLog.Log("should Queue");
                            Lua.DoString("C_PetBattles.StartPVPMatchmaking()");
                            BBLog.LogAlways("Queued for PVP match");
                            _Timer.Reset();
                            _Timer.Start();
                            _PvpTimer = 0;
                        }
                    }
                    //Heb ik invite?
                }
                if (!InPetCombat() && WildBattleTarget() != null) {
                    //Bandages? Pet Rez Skill?
                    ///cast Revive Battle Pets           BattleBuddy.MySettings.UseHealSkill
                    if (_HealTimer.ElapsedMilliseconds > 2000 && (SpellManager.CanCast("Revive Battle Pets") || !SpellManager.CanCast("Revive Battle Pets"))) {
                        _HealTimer.Stop();
                        _HealTimer.Reset();
                        _HealTimer.Start();

                        //do i actually need heals?
                        int dumdum2 = 0;
                        if (GetPetHPPreCombat(1) < 40) dumdum2++;
                        if (GetPetHPPreCombat(2) < 40) dumdum2++;
                        if (GetPetHPPreCombat(3) < 40) dumdum2++;
                        if (dumdum2 > 2) {
                            BBLog.LogTrace(GetPetHPPreCombat(1) + "Injured pets quite high: " + dumdum2 + " Making sure its not due to lag");
                            Lua.DoString("local dummy = C_PetJournal.PetIsHurt(1)");
                            Lua.DoString("local dummy = C_PetJournal.PetIsHurt(2)");
                            Lua.DoString("local dummy = C_PetJournal.PetIsHurt(3)");
                            dumdum2 = 0;
                            if (GetPetHPPreCombat(1) < 40) dumdum2++;
                            if (GetPetHPPreCombat(2) < 40) dumdum2++;
                            if (GetPetHPPreCombat(3) < 40) dumdum2++;
                        }
                        //Heal
                        if (dumdum2 >= BattleBuddy._MySettings.UseHealSkill) {
                            if (!SpellManager.CanCast("Revive Battle Pets")) {
                                if (SpellManager.Spells["Revive Battle Pets"].CooldownTimeLeft.TotalMilliseconds > 60000) {
                                    if (dumdum2 >= BattleBuddy._MySettings.UseBandagesToHeal && BattleBuddy._MySettings.UseBandagesToHeal > 0) {
                                        Lua.DoString("RunMacroText(\"/use Battle Pet Bandage\");");
                                        BBLog.Log("Enough pets injured, Using Bandages");
                                    }
                                }
                            }
                            BBLog.Log("Enough pets injured, trying to heal/rez pets");
                            if (SpellManager.CanCast(125439)) SpellManager.Cast(125439);
                            //StyxWoW.Sleep(300);
                        }
                    }

                    int dumdum3 = 0;
                    if (GetPetHPPreCombat(1) < 20) dumdum3++;
                    if (GetPetHPPreCombat(2) < 20) dumdum3++;
                    if (GetPetHPPreCombat(3) < 20) dumdum3++;
                    BBLog.Log("Pet HP's : " + GetPetHPPreCombat(1) + ":" + GetPetHPPreCombat(2) + ":" + GetPetHPPreCombat(3));
                    if (dumdum3 > 0) BBLog.Log("Heavily injured pets : " + dumdum3);
                    if ((3 - dumdum3) >= BattleBuddy._MySettings.MinPetsAlive) {
                        if (WildBattleTarget().Distance > 8) {
                            // Move to target
                            Stopwatch escapetimer = new Stopwatch();
                            escapetimer.Start();

                            _PriorFramelock = GlobalSettings.Instance.UseFrameLock;
                            GlobalSettings.Instance.UseFrameLock = false;

                            using (StyxWoW.Memory.ReleaseFrame())
                                while (WildBattleTarget().Distance > 10 && !Styx.StyxWoW.Me.Combat && escapetimer.ElapsedMilliseconds < 10000) {
                                    //ObjectManager.Update();
                                    Pulsator.Pulse(PulseFlags.Objects);
                                    //if (Styx.StyxWoW.Me.Combat) return;
                                    BBLog.LogTrace("Move to spot");
                                    if (_MoveTimer.ElapsedMilliseconds > 500) {
                                        _MoveTimer.Stop();
                                        _MoveTimer.Reset();
                                        _MoveTimer.Start();

                                        if (Styx.StyxWoW.Me.IsFlying) Styx.WoWInternals.WoWMovement.ClickToMove(WildBattleTarget().Location.X, WildBattleTarget().Location.Y, WildBattleTarget().Location.Z + 3);
                                        if (!Styx.StyxWoW.Me.IsFlying) Navigator.MoveTo(WildBattleTarget().Location);

                                    }

                                    if (_StuckTimer.ElapsedMilliseconds > 1000 && _OldLocation.Distance(Styx.StyxWoW.Me.Location) < 0.5) {
                                        if (!Styx.StyxWoW.Me.Combat) {
                                            _BlacklistCounter++;
                                            BBLog.LogTrace("STUCK : Blacklist counter :" + _BlacklistCounter);
                                            if (_BlacklistCounter > BattleBuddy._MySettings.BlacklistCounterLimit) {
                                                BBLog.Log("Could not get close enough to engage. Blacklisting " + WildBattleTarget().Name);
                                                //Blacklist.Add(WildBattleTarget().Guid, TimeSpan.FromMinutes(1));
                                                Blacklist.Add(WildBattleTarget().Guid, BlacklistFlags.Interact, TimeSpan.FromMinutes(1), "Could not get close");
                                                _BlacklistCounter = 0;
                                            }
                                        }
                                    }
                                    if (_StuckTimer.ElapsedMilliseconds > 1000) {
                                        _StuckTimer.Stop();
                                        _StuckTimer.Reset();
                                        _StuckTimer.Start();
                                        _OldLocation = StyxWoW.Me.Location;
                                    }
                                }
                            GlobalSettings.Instance.UseFrameLock = _PriorFramelock;
                        }

                        if (_InteractTimer.ElapsedMilliseconds > 1000 && WildBattleTarget().Distance < 12) {
                            _InteractTimer.Stop();
                            _InteractTimer.Reset();
                            _InteractTimer.Start();

                            //Preparation, like swapping pets for bonusses
                            SetPetAbilities();
                            BBLog.LogAlways("Battle Preparation");
                            _BattleRoundNumber = 0;
                            if (!Styx.StyxWoW.Me.Combat && _OldGuid == WildBattleTarget().Guid) {
                                _BlacklistCounter++;
                                BBLog.LogTrace("Trying to interact. Blacklist counter :" + _BlacklistCounter);
                                if (_BlacklistCounter > BattleBuddy._MySettings.BlacklistCounterLimit) {
                                    BBLog.LogTrace("Could not interact. Blacklisting" + WildBattleTarget().Name);
                                    Blacklist.Add(WildBattleTarget().Guid, TimeSpan.FromMinutes(1));
                                    _BlacklistCounter = 0;

                                }
                            }
                            _OldGuid = WildBattleTarget().Guid;

                            try {
                                if (_MySettings.DoPreCombatSwapping) PetSwappingPreCombat();
                            } catch (Exception ex) { BBLog.LogException(ex); }

                            if (Styx.StyxWoW.Me.Mounted) Styx.CommonBot.Mount.Dismount();
                            BBLog.LogTrace("Attempting to start Wild Pet Battle");
                            WildBattleTarget().Interact();
                        }
                    }
                }

                //using (new TemporaryHardLockRelease())
                bool imlocked = false;
                while (TreeRoot.IsRunning && !imlocked && InPetCombat()) {
                    imlocked = GlobalSettings.Instance.UseFrameLock;
                    try {
                        Styx.Helpers.GlobalSettings.Instance.LogoutForInactivity = false;

                        Lua.DoString("if C_PetBattles.GetPVPMatchmakingInfo()=='proposal' then C_PetBattles.AcceptQueuedPVPMatch() end");
                        _BlacklistCounter = 0;

                        //Actual battle!
                         BBLog.LogTrace("In Pet Combat against rarity "+GetRarity()+" and I can trap"+ CanTrap());
                         BBLog.LogTrace("In Combat");
                        if (MustSelectNew() && _SwapTimer.ElapsedMilliseconds > 3000) {
                            BBLog.LogTrace("Have to select new one");
                            try {
                                if (_MySettings.UseRatingSystem) ForcedSwapping();
                                if (!_MySettings.UseRatingSystem) DoSimpleRotate();
                            } catch (Exception e) {
                                BBLog.LogException(e);
                            }
                            _SwapTimer.Stop();
                            _SwapTimer.Reset();
                            _SwapTimer.Start();

                        }

                        int minrarity = BattleBuddy._MySettings.GetRarity;
                        if (minrarity > 4) {
                            minrarity = GetRarityBySpeciesID(GetCurrentEnemySpecies());
                            if (minrarity < 1) minrarity = 1;
                        }

                        if (GetRarity() > minrarity && CanTrap()) {
                            if (CanFight()) Lua.DoString("C_PetBattles.UseTrap()");
                        } else {
                            if (_LogicTimer.ElapsedMilliseconds > 500 && CanFight()) {
                                if (CanCastSomething()) {
                                    DoCombatRoutine();
                                    //StyxWoW.Sleep(200);
                                } else {
                                    _LogicTimer.Stop();
                                    _LogicTimer.Reset();
                                    _LogicTimer.Start();
                                    BBLog.LogTrace("No action available, wait for next pulse.");
                                    //Lua.DoString("C_PetBattles.SkipTurn()");
                                }
                            }
                        }
                    } catch (Exception exc) {
                        BBLog.LogException(exc);
                        return;
                    }

                }
            }
        }

        private bool MinimumRequirementsMet()
        {
            List<string> petsequipped = Lua.GetReturnValues(
                "local dummy=3 " +
                "if C_PetJournal.GetPetLoadOutInfo(1)==nil then dummy=dummy-1 end " +
                "if C_PetJournal.GetPetLoadOutInfo(2)==nil then dummy=dummy-1 end " +
                "if C_PetJournal.GetPetLoadOutInfo(3)==nil then dummy=dummy-1 end " +
                "return dummy");
            if (petsequipped[0] != "3") {
                BBLog.LogAlways("Pets Equipped " + petsequipped[0]);
                BBLog.LogAlways("This is NOT ENOUGH for this plugin to function. Equip 3 pets and learn the rez pet skill.");
                return false;
            }
            return true;
        }

        private void UpdatePetSlot()
        {
            string fav = "";

            if (!_MySettings.Slot1SwapEnabled) return;
            //BBLog.LogTrace("Checking slot 1 level");

            if (GetPetLevelPreCombat(1) >= _MySettings.Slot1SwapMaxLevel || GetPetHPPreCombat(1) == 0) {
                BBLog.LogTrace("Going to switch slot 1");
                Lua.DoString("C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_FAVORITES, false) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_COLLECTED, true) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_NOT_COLLECTED, true) ");
                Lua.DoString("C_PetJournal.ClearSearchFilter() C_PetJournal.AddAllPetSourcesFilter() C_PetJournal.AddAllPetTypesFilter() ");

                if (_MySettings.Slot1SwapFavoriteOnly) {
                    fav = fav + "and favorite == true ";
                }
                if (_MySettings.Slot1TradeableOnly) {
                    fav = fav + "and isTradeable == true ";
                }

                fav = fav + "and isWild == " + _MySettings.Slot1AllowWild.ToString().ToLower() + " ";

                string luastring = "view, total = C_PetJournal.GetNumPets() for wantlevel=" + _MySettings.Slot1SwapMinLevel + "," + (_MySettings.Slot1SwapMaxLevel - 1) + " do for i=1, total do petID, _, owned, _, level, favorite, _, _, _, _, _, _, _, isWild, canBattle, isTradeable, _, _ = C_PetJournal.GetPetInfoByIndex(i) if (petID ~= nil) then health, maxHealth, power, speed, rarity = C_PetJournal.GetPetStats(petID) if (health == maxHealth and level==wantlevel " + fav + "and owned == true and canBattle==true) then C_PetJournal.SetPetLoadOutInfo(1,petID) return end end end end ";
                BBLog.LogTrace(luastring);
                Lua.DoString(luastring);
            }
        }


        private void SetBot(string tofind)
        {
            return;
        }


        private void SetBotBase(object b)
        {
            string tofind = (string)b;
            BBLog.Log("Attempting switch to " + tofind);
            if (BotManager.Current.Name.Contains(tofind)) return;
            while (TreeRoot.IsRunning) {
                BBLog.Log("Stopping " + BotManager.Current.Name);
                TreeRoot.Stop();
                StyxWoW.Sleep(1000);
            }

            foreach (KeyValuePair<string, BotBase> Base in BotManager.Instance.Bots) {
                if (Base.Key.ToLower().Contains(tofind.ToLower())) {
                    BBLog.Log("Attempting to start " + Base.Key);
                    BotManager.Instance.SetCurrent(Base.Value);
                    if (!BotManager.Current.Initialized) BotManager.Current.Initialize();
                    StyxWoW.Sleep(500);
                }
            }

            StyxWoW.Sleep(500);
            BBLog.Log("Starting " + BotManager.Current.Name);
            while (!TreeRoot.IsRunning) {
                TreeRoot.Start();
                StyxWoW.Sleep(500);
            }
        }


        private void DoSimpleRotate()
        {

            if (_TempOrder == "") _TempOrder = _MySettings.PetOrder;
            string dummm = _TempOrder;
            string[] orders = dummm.Split(',');

            bool doneit = false;
            _TempOrder = "";
            foreach (string order in orders) {
                if (doneit) {
                    if (_TempOrder != "") _TempOrder = _TempOrder + "," + order;
                    if (_TempOrder == "") _TempOrder = order;
                }
                if (CanSelect(int.Parse(order))) {
                    CombatCallPet(int.Parse(order));
                    doneit = true;
                }
            }
        }


        private void DoCombatRoutine()
        {
            int getrari = BattleBuddy._MySettings.GetRarity;
            if (getrari > 4) getrari = 2;
            _BattleRoundNumber++;
            if (BattleBuddy._MySettings.ForfeitIfNotInteresting) {
                List<string> forfeit = Lua.GetReturnValues("if C_PetBattles.GetBreedQuality(2,1) <= " + getrari + " and C_PetBattles.GetBreedQuality(2,2) <= " + getrari + " and C_PetBattles.GetBreedQuality(2,3) <= " + getrari + " and  C_PetBattles.IsWildBattle() == true then C_PetBattles.ForfeitGame() return 1 end return 0");
            }

            bool didlogic = false;
            try {
                BBLog.Log("Loading logic for " + ReadActiveSlotSpecies());
            } catch (Exception ) {
                // we cna reach this point if there is a race between pulse and end of the battle,
                //  if we do, just continue processing
                BBLog.LogWarning("Hit race in DoCombatRoutine");
            }

            _PetSettings.Logic = GetEquippedOrDefaultLogic(ReadActiveSlot(), ReadActiveSlotSpecies()).Replace("@ @", "@").Replace("@ @", "@").Replace("@@", "@").Replace("@@", "@");

            string dumdum = "";
            Stopwatch dummy = new Stopwatch();
            dummy.Start();

            if (!_MySettings.DetailedLogging) {
                dumdum = PreParsing(_DefaultLogicz.Logic + "@" + _PetSettings.Logic);
            } else {
                dumdum = _DefaultLogicz.Logic + "@" + _PetSettings.Logic;
            }

            string[] PetLogics = dumdum.Split('@');
            bool stopdoingstuff = false;
            BBLog.LogAlways("Battle: Round " + _BattleRoundNumber);

            foreach (string alogic in PetLogics) {
                bool succeeded = ParseLogic(alogic);

                if (succeeded) {
                    if (!stopdoingstuff && (String.Compare(alogic.Substring(0, 7), "SWAPOUT") == 0) && _SwapTimer.ElapsedMilliseconds > 500) {
                        _SwapTimer.Stop();
                        _SwapTimer.Reset();
                        _SwapTimer.Start();

                        if (!_MySettings.UseRatingSystem) {
                            BBLog.Log("Using simple rotate");
                            DoSimpleRotate();
                        } else {
                            BBLog.Log("Using advanced rating system");
                            try {
                                WantSwapping();
                            } catch (Exception e) {
                                BBLog.LogException(e);
                            }
                        }
                        stopdoingstuff = true;
                    }

                    if ((String.Compare(alogic.Substring(0, 12), "CASTSPELL(1)") == 0)) Lua.DoString("C_PetBattles.UseAbility(1)");
                    if ((String.Compare(alogic.Substring(0, 12), "CASTSPELL(2)") == 0)) Lua.DoString("C_PetBattles.UseAbility(2)");
                    if ((String.Compare(alogic.Substring(0, 12), "CASTSPELL(3)") == 0)) Lua.DoString("C_PetBattles.UseAbility(3)");
                    if ((String.Compare(alogic.Substring(0, 8), "PASSTURN") == 0)) Lua.DoString("C_PetBattles.SkipTurn()");
                    if ((String.Compare(alogic.Substring(0, 7), "FORFEIT") == 0)) { Lua.DoString("C_PetBattles.ForfeitGame()"); return; }

                    didlogic = true;
                    _SkipCounter = 0;
                }
            }

            dummy.Stop();
            BBLog.LogTrace("time elapsed " + dummy.ElapsedMilliseconds);
            dummy.Reset();

            BBLog.LogTrace("----------------------------------------------------------------");
            BBLog.LogTrace("FINISHED Logics");
            BBLog.LogTrace("----------------------------------------------------------------");

            if (didlogic) {
                _LogicTimer.Stop();
                _LogicTimer.Reset();
                _LogicTimer.Start();
            }

            if (!didlogic) {
                if (!PetCanCast(1) && !PetCanCast(2) && !PetCanCast(3)) {
                }
                _SkipCounter++;
                BBLog.LogTrace("SKIP count :" + _SkipCounter);
                //StyxWoW.Sleep(1500);
                if (_SkipCounter > BattleBuddy._MySettings.SkipCounterLimit) {
                    Lua.DoString("C_PetBattles.SkipTurn()");
                    _SkipCounter = 0;
                    BBLog.LogTrace("SKIPPED!!!");
                }
            }
        }



        public static void BlacklistLoad()
        {
            _TheBlacklist.Clear();

            try {
                StreamReader Read = new StreamReader(Convert.ToString(_BlacklistPath));
                while (Read.Peek() >= 0) {
                    string pline = Read.ReadLine();
                    if (pline != null) {
                        _TheBlacklist.Add(pline.ToLower());
                    }
                }
                Read.Close();
            } catch (Exception ex) {
                MessageBox.Show(Convert.ToString(ex.Message));
                return;
            }
        }



        public static void WhitelistLoad()
        {
            _TheWhitelist.Clear();
            try {
                StreamReader Read = new StreamReader(Convert.ToString(_WhitelistPath));
                while (Read.Peek() >= 0) {
                    string pline = Read.ReadLine();
                    if (pline != null) {
                        _TheWhitelist.Add(pline.ToLower());

                    }
                }
                Read.Close();
            } catch (Exception ex) {
                MessageBox.Show(Convert.ToString(ex.Message));
                return;
            }
        }


        public void PrintSettings()
        {
            if (BattleBuddy._MySettings.DetailedLogging) {
                BBLog.LogAlways("Detailed logging is ON");
            } else {
                BBLog.LogAlways("Detailed logging is OFF");
            }

            if (BattleBuddy._MySettings.DetailedLogging) {
                BBLog.Log("**************************************************************************************");
                BBLog.Log("Settings :");
                Settings set = _MySettings;
                if (set == null)
                    return;
                foreach (var kvp in set.GetSettings()) {
                    BBLog.Log(String.Format("  {0}: {1}", kvp.Key, kvp.Value.ToString()));
                }
                List<string> cnt = Lua.GetReturnValues(
                    "local dummy=3 " +
                    "if C_PetJournal.GetPetLoadOutInfo(1)==nil then dummy=dummy-1 end " +
                    "if C_PetJournal.GetPetLoadOutInfo(2)==nil then dummy=dummy-1 end " +
                    "if C_PetJournal.GetPetLoadOutInfo(3)==nil then dummy=dummy-1 end " +
                    "return dummy");
                BBLog.Log("Pets Equipped " + cnt[0]);
                BBLog.Log("**************************************************************************************");
            }
        }



        public string GetEquippedOrDefaultLogic(string petID, string speciesID)
        {
            Librarian.Librarian lib = new Librarian.Librarian(Name);


            if (!DigitsOnly(speciesID)) speciesID = GetSpeciesByName(speciesID);
            string dummy = "SWAPOUT Health(THISPET) ISLESSTHAN 30@CASTSPELL(1) COOLDOWN(SKILL(1)) EQUALS false";


            string cs = "URI=file:" + _PetLogicsDbPath;

            using (SQLiteConnection con = new SQLiteConnection(cs)) {
                con.Open();
                string stm = "";

                stm = "SELECT LogicID FROM PetSelection WHERE PetID = '" + petID + "'";
                string returned = "-1";

                using (SQLiteCommand cmd = new SQLiteCommand(stm, con)) {
                    using (SQLiteDataReader rdr = cmd.ExecuteReader()) {
                        if (rdr.HasRows) {
                            while (rdr.Read()) {
                                string cel1 = rdr.GetString(0);

                                returned = cel1;

                            }

                        }
                    }
                }

                string whattodo = "";
                if (returned == "-1") {
                    if (IsThisAPuppy()) return lib.GeneratePuppyLogic(GetEquippedOrDefaultSpellset(petID, speciesID));

                    whattodo = "SpeciesID = " + speciesID + " AND isDefault = 1";
                } else {
                    whattodo = "ID = '" + returned + "'";
                }

                stm = "SELECT Logic FROM Logics WHERE " + whattodo;
                using (SQLiteCommand cmd = new SQLiteCommand(stm, con)) {
                    using (SQLiteDataReader rdr = cmd.ExecuteReader()) {
                        if (rdr.HasRows) {
                            while (rdr.Read()) {
                                string cel1 = rdr.GetString(0);
                                dummy = cel1;
                            }
                        }
                    }
                }
                con.Close();
            }


            // ?? Hardcoded string check used for puppies?
            if (dummy == "SWAPOUT Health(THISPET) ISLESSTHAN 30@CASTSPELL(1) COOLDOWN(SKILL(1)) EQUALS false") {
                if (IsThisAPuppy()) return lib.GeneratePuppyLogic(GetEquippedOrDefaultSpellset(petID, speciesID));

                dummy = lib.GenerateLogic(GetEquippedOrDefaultSpellset(petID, speciesID));
            }
            return dummy;
        }



        static bool DigitsOnly(string s)
        {
            foreach (char c in s) {
                if (c < '0' || c > '9')
                    return false;
            }
            return true;
        }



        public string GetEquippedOrDefaultSpellset(string petID, string speciesID)
        {
            string dummy = "ASSIGNABILITY1(0)@ASSIGNABILITY2(0)@ASSIGNABILITY3(0)";
            try {
                if (!DigitsOnly(speciesID)) speciesID = GetSpeciesByName(speciesID);
                string cs = "URI=file:" + _PetLogicsDbPath;

                using (SQLiteConnection con = new SQLiteConnection(cs)) {
                    con.Open();
                    string stm = "";

                    stm = "SELECT LogicID FROM PetSelection WHERE PetID = '" + petID + "'";
                    string returned = "-1";

                    using (SQLiteCommand cmd = new SQLiteCommand(stm, con)) {
                        using (SQLiteDataReader rdr = cmd.ExecuteReader()) {
                            if (rdr.HasRows) {
                                while (rdr.Read()) {
                                    string cel1 = rdr.GetString(0);

                                    returned = cel1;

                                }

                            }
                        }
                    }

                    string whattodo = "";
                    if (returned == "-1") {
                        whattodo = "SpeciesID = " + speciesID + " AND isDefault = 1";

                        if (_MySettings.AllowRoleDetect) {
                            //iets anders  whattodo = "SpeciesID = " + speciesID + " AND isDefault = 1";
                        }
                    } else {
                        whattodo = "ID = '" + returned + "'";
                    }

                    stm = "SELECT Spellset FROM Logics WHERE " + whattodo;

                    using (SQLiteCommand cmd = new SQLiteCommand(stm, con)) {
                        using (SQLiteDataReader rdr = cmd.ExecuteReader()) {
                            if (rdr.HasRows) {
                                while (rdr.Read()) {
                                    string cel1 = rdr.GetString(0);
                                    dummy = cel1;
                                }
                            }
                        }
                    }
                    con.Close();
                }
            } catch (Exception e) {
                BBLog.LogException(e);
            }

            if (dummy == "ASSIGNABILITY1(0)@ASSIGNABILITY2(0)@ASSIGNABILITY3(0)") {
                List<string> cntskillz = Lua.GetReturnValues("for i=1,3 do local petID, ability1ID, ability2ID, ability3ID, locked = C_PetJournal.GetPetLoadOutInfo(i) if (tonumber(petID,16)==" + petID + ") then return ability1ID, ability2ID, ability3ID end end return 0,0,0");
                string spelllayout = "ASSIGNABILITY1(" + cntskillz[0] + ")@" +
                                     "ASSIGNABILITY2(" + cntskillz[1] + ")@" +
                                     "ASSIGNABILITY3(" + cntskillz[2] + ")";
                dummy = spelllayout;
            }

            return dummy;
        }



        public static void LoadPetSettings(string petID, string speciesID)
        {
            BBLog.LogTrace("Loading settings for " + petID);

            string filename = GetPetSettingsFilePath(petID);
            if (!File.Exists(filename)) {
                BBLog.Log(BBLog.LogType.LOG_WARN, "Warn: " + petID + " not found, trying species: " + speciesID);
                string filename2 = GetPetSettingsFilePath(speciesID);
                if (File.Exists(filename2)) {
                    File.Copy(filename2, filename);
                }
            }

            try {
                _PetSettings = new PetBattleSettings(filename);
            } catch (Exception ex) { BBLog.LogException(ex); }

            _PetSettings.Logic = ConvertFromOldFile(_PetSettings.Logic);
            _PetSettings.Save();
        }


        public static string GetPetSettingsFilePath(string petID)
        {
            return Path.Combine(_PetSettingsPath, petID) + ".xml";
        }

        public static void LoadPetSettingsBN(string petID)
        {
            try {
                _PetSettings = new PetBattleSettings(GetPetSettingsFilePath(petID));
            } catch (Exception ex) { BBLog.LogException(ex); }

            _PetSettings.Logic = ConvertFromOldFile(_PetSettings.Logic);
            _PetSettings.Save();
        }



        public static void LoadPetbyFile(string petID)
        {
            string filename = petID;

            try {
                _PetSettings = new PetBattleSettings(filename);
            } catch (Exception ex) { BBLog.LogException(ex); }

            _PetSettings.Logic = ConvertFromOldFile(_PetSettings.Logic);
            _PetSettings.Save();
        }



        public static void LoadDefaultLogic()
        {
            try {
                _DefaultLogicz = new PetBattleSettings(_DefaultLogicPath);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
        }



        public static bool ActualCalc(string s)
        {
            if (s == "" || s == null) return false;
            var ce = new CalcEngine.CalcEngine();
            var value = false;

            try {
                var x = ce.Parse(s);
                value = (bool)x.Evaluate();
            } catch (Exception exc) {
                BBLog.LogError("Failed parse or evaluate of string: " + s);
            }
            return value;
        }



        public static int Calculate(string s)
        {
            var ce = new CalcEngine.CalcEngine();
            var x = ce.Parse(s);
            var value = x.Evaluate();
            return Int32.Parse(value.ToString());
        }



        public static bool Calc(string s)
        {
            char[] delimit = new char[] { '&' };
            string s10 = s;
            foreach (string substr in s10.Split(delimit)) {
                if (!ActualCalc(substr)) return false;
            }
            return true;
        }



        public void WantSwapping()
        {
            if (GetPetHealth(1) < 25 && GetPetHealth(2) < 25 && GetPetHealth(3) < 25) {
                if (GetCurrentPetHealth() > 0) return;
                if (CanSelect(3)) { CombatCallPet(3); return; }
                if (CanSelect(2)) { CombatCallPet(2); return; }
                if (CanSelect(1)) { CombatCallPet(1); return; }
            }
            int slot1rating = 0;
            int slot2rating = 0;
            int slot3rating = 0;

            slot1rating = BattleRating(GetPetLevel(1), GetPetHealth(1), ReadSlot(1), GetCurrentEnemyType(), GetCurrentEnemyLevel());

            slot2rating = BattleRating(GetPetLevel(2), GetPetHealth(2), ReadSlot(2), GetCurrentEnemyType(), GetCurrentEnemyLevel());
            slot3rating = BattleRating(GetPetLevel(3), GetPetHealth(3), ReadSlot(3), GetCurrentEnemyType(), GetCurrentEnemyLevel());

            if (!CanSelect(1)) slot1rating = slot1rating - 100000;
            if (!CanSelect(2)) slot2rating = slot2rating - 100000;
            if (!CanSelect(3)) slot3rating = slot3rating - 100000;

            BBLog.Log("Pet Ratings - Slot 1 : " + slot1rating + " " + "Slot 2 : " + slot2rating + " " + "Slot 3 : " + slot3rating);
            if (slot1rating >= slot2rating && slot1rating >= slot3rating) CombatCallPet(1);
            if (slot2rating >= slot1rating && slot2rating >= slot3rating) CombatCallPet(2);
            if (slot3rating >= slot2rating && slot3rating >= slot1rating) CombatCallPet(3);
        }



        public void ForcedSwapping()
        {
            int slot1rating = 0;
            int slot2rating = 0;
            int slot3rating = 0;

            if (CanSelect(1)) slot1rating = BattleRating(GetPetLevel(1), GetPetHealth(1), ReadSlot(1), GetCurrentEnemyType(), GetCurrentEnemyLevel());

            if (CanSelect(2)) slot2rating = BattleRating(GetPetLevel(2), GetPetHealth(2), ReadSlot(2), GetCurrentEnemyType(), GetCurrentEnemyLevel());
            if (CanSelect(3)) slot3rating = BattleRating(GetPetLevel(3), GetPetHealth(3), ReadSlot(3), GetCurrentEnemyType(), GetCurrentEnemyLevel());

            if (!CanSelect(1)) slot1rating = slot1rating - 100000;
            if (!CanSelect(2)) slot2rating = slot2rating - 100000;
            if (!CanSelect(3)) slot3rating = slot3rating - 100000;
            BBLog.Log("Pet Ratings - Slot 1 : " + slot1rating + " " + "Slot 2 : " + slot2rating + " " + "Slot 3 : " + slot3rating);

            if (slot1rating >= slot2rating && slot1rating >= slot3rating) CombatCallPet(1);
            if (slot2rating >= slot1rating && slot2rating >= slot3rating) CombatCallPet(2);
            if (slot3rating >= slot2rating && slot3rating >= slot1rating) CombatCallPet(3);
        }



        private void PokeSleep(int time)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            while (sw.ElapsedMilliseconds < time) {
                Pulsator.Pulse(PulseFlags.Objects);
            }
        }



        public void PetSwappingPreCombat()
        {
            BBLog.LogTrace("Entered Pet Swapping function");

            int tartype = GetTypeByTarget();
            int tarlevel = GetLevelByTarget();
            int slot1rating = BattleRating(GetPetLevelPreCombat(1), GetPetHPPreCombat(1), ReadSlot(1), tartype, tarlevel);
            int slot2rating = BattleRating(GetPetLevelPreCombat(2), GetPetHPPreCombat(2), ReadSlot(2), tartype, tarlevel);
            int slot3rating = BattleRating(GetPetLevelPreCombat(3), GetPetHPPreCombat(3), ReadSlot(3), tartype, tarlevel);
            BBLog.Log("Pet Ratings - Slot 1 : " + slot1rating + " " + "Slot 2 : " + slot2rating + " " + "Slot 3 : " + slot3rating);

            if (slot1rating < slot2rating || slot1rating < slot3rating) {
                //swap pet 
                BBLog.LogTrace("Swapping something");
                if (slot2rating >= slot3rating) SetSlot(1, 2);
                if (slot2rating < slot3rating) SetSlot(1, 3);
                //StyxWoW.Sleep(1000);

            } else {
                BBLog.Log("No swap needed");
            }
        }



        public bool IsBattlePet(WoWUnit tar)
        {
            if (tar.CreatureType.ToString() == "14") return true;
            return false;
        }



        public int GetTypeByTarget()
        {
            List<string> cnt = Lua.GetReturnValues("local dummy=UnitBattlePetType('target') if dummy==nil then dummy=0 end return dummy");
            int getal = 0;
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }

            return getal;
        }



        public int GetLevelByTarget()
        {
            List<string> cnt = Lua.GetReturnValues("local dummy=UnitBattlePetLevel('target') if dummy==nil then dummy=0 end return dummy");
            int getal = 0;
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }


        public void SetSlot(int slot, int fromslot)
        {
            Lua.DoString("local petID= C_PetJournal.GetPetLoadOutInfo(" + fromslot + ") C_PetJournal.SetPetLoadOutInfo(" + slot + ", petID)");
        }



        public void CombatCallPet(int petnum)
        {
            Lua.DoString("if C_PetBattles.GetActivePet(1) ~= " + petnum + " then C_PetBattles.ChangePet(" + petnum + ") end");
        }



        public int GetCurrentPetHealth()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetHealth(1,C_PetBattles.GetActivePet(1))");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            int getal2 = 0;
            List<string> cnt2 = Lua.GetReturnValues("return C_PetBattles.GetMaxHealth(1,C_PetBattles.GetActivePet(1))");
            try {
                getal2 = int.Parse(cnt2[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }

            getal = getal * 100;
            getal = getal / getal2;
            return getal;
        }



        public static int GetPetHPPreCombat(int petnum)
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("local petID= C_PetJournal.GetPetLoadOutInfo(" + petnum + ") local health, maxHealth, attack, speed, rarity = C_PetJournal.GetPetStats(petID) local dummy = (health / maxHealth) * 100 return dummy");

            try {
                cnt[0].Replace(",", ".");
                int i = cnt[0].IndexOf('.');

                // Remainder of string starting at 'c'.
                if (i > -1) cnt[0] = cnt[0].Substring(0, i);
                BBLog.LogTrace("Lua received HP :"+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public static int GetPetHealth(int petnum)
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetHealth(1," + petnum + ")");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }

            int getal2 = 0;
            List<string> cnt2 = Lua.GetReturnValues("return C_PetBattles.GetMaxHealth(1," + petnum + ")");

            try {
                getal2 = int.Parse(cnt2[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }

            // Convert to percentage
            getal = getal * 100;
            getal = getal / getal2;
            return getal;
        }



        public int GetEnHealth()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("local dummy=0 if (C_PetBattles.GetActivePet(2) > 0) then dummy= C_PetBattles.GetHealth(2,C_PetBattles.GetActivePet(2)) end return dummy");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            int getal2 = 0;
            List<string> cnt2 = Lua.GetReturnValues("local dummy=0 if (C_PetBattles.GetActivePet(2) > 0) then dummy= C_PetBattles.GetMaxHealth(2,C_PetBattles.GetActivePet(2)) end return dummy");
            try {
                getal2 = int.Parse(cnt2[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            getal = getal * 100;
            getal = getal / getal2;
            return getal;
        }


        public string GetCurrentEnemyName()
        {
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetName(2,C_PetBattles.GetActivePet(2))");

            return cnt[0];
        }



        public int GetCurrentEnemyType()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetPetType(2,C_PetBattles.GetActivePet(2))");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public string GetCurrentEnemySpecies()
        {
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetPetSpeciesID(2,C_PetBattles.GetActivePet(2))");
            return cnt[0];
        }




        public int GetCurrentSpeed()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("local dummy = C_PetBattles.GetSpeed(1,C_PetBattles.GetActivePet(1)) if dummy > 0 then return dummy end return 0");
            try {
                BBLog.LogTrace("Speed: "+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetCurrentEnemySpeed()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("local dummy = C_PetBattles.GetSpeed(2,C_PetBattles.GetActivePet(2)) if dummy > 0 then return dummy end return 0");
            try {
                BBLog.LogTrace("Enemy Speed"+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetCurrentEnemyLevel()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetLevel(2,C_PetBattles.GetActivePet(2))");
            try {
                BBLog.LogTrace("Enemy Level: "+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetPetLevel(int petnum)
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetLevel(1," + petnum + ")");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetCurrentPetLevel()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetLevel(1,C_PetBattles.GetActivePet(1))");
            try {
                BBLog.LogTrace("Pet Level: "+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetCurrentEnemyPetLevel()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetLevel(2,C_PetBattles.GetActivePet(2))");
            try {
                BBLog.LogTrace("Enemy Pet Level: "+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public static int GetPetLevelPreCombat(int petnum)
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("local petID= C_PetJournal.GetPetLoadOutInfo(" + petnum + ") local speciesID, customName, level, xp, maxXp, displayID, petName, petIcon, petType, creatureID = C_PetJournal.GetPetInfoByPetID(petID) return level;");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }




        public int GetCurrentEnemyHealth()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetHealth(2,C_PetBattles.GetActivePet(2))");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetCurrentEnemyMaxHealth()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetMaxHealth(2,C_PetBattles.GetActivePet(2))");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetRarity()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetBreedQuality(2,C_PetBattles.GetActivePet(2))");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public int GetRarityByNum(int petnum)
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetBreedQuality(2," + petnum + ")");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public void SetPetAbilities()
        {
            //For each pet
            for (int i = 1; i < 4; i++) {
                _PetSettings.SpellLayout = GetEquippedOrDefaultSpellset(ReadSlot(i), ReadSlotSpecies(i));
                if (_PetSettings.SpellLayout == "") _PetSettings.SpellLayout = "ASSIGNABILITY1(0)@ASSIGNABILITY2(0)@ASSIGNABILITY3(0)";
                //parse settings looking for AssignAbility1, AssignAbility2, AssignAbility3
                string dumdum = _PetSettings.SpellLayout;

                string[] PetLogics = dumdum.Split('@');

                foreach (string alogic in PetLogics) {
                    if ((String.Compare(alogic.Substring(0, 15), "ASSIGNABILITY1(") == 0)) {
                        int FirstChr = alogic.IndexOf("ASSIGNABILITY1(") + 15;
                        int SecondChr = alogic.IndexOf(")", FirstChr);
                        string strTemp = alogic.Substring(FirstChr, SecondChr - FirstChr);

                        if (int.Parse(strTemp) > 0) SetAbility(i, 1, int.Parse(strTemp));
                    }
                    if ((String.Compare(alogic.Substring(0, 15), "ASSIGNABILITY2(") == 0)) {
                        int FirstChr = alogic.IndexOf("ASSIGNABILITY2(") + 15;
                        int SecondChr = alogic.IndexOf(")", FirstChr);
                        string strTemp = alogic.Substring(FirstChr, SecondChr - FirstChr);

                        if (int.Parse(strTemp) > 0) SetAbility(i, 2, int.Parse(strTemp));
                    }
                    if ((String.Compare(alogic.Substring(0, 15), "ASSIGNABILITY3(") == 0)) {
                        int FirstChr = alogic.IndexOf("ASSIGNABILITY3(") + 15;
                        int SecondChr = alogic.IndexOf(")", FirstChr);
                        string strTemp = alogic.Substring(FirstChr, SecondChr - FirstChr);

                        if (int.Parse(strTemp) > 0) SetAbility(i, 3, int.Parse(strTemp));
                    }
                }
            }
        }



        public void SetAbility(int petSlot, int abilitySlot, int spellID)
        {
            BBLog.Log("Setting custom ability Pet slot: " + petSlot + " Ability slot:" + abilitySlot + " Spell ID:" + spellID + ")");
            Lua.DoString("petGUID = C_PetJournal.GetPetLoadOutInfo(" + petSlot + ") speciesID, customName, level = C_PetJournal.GetPetInfoByPetID(petGUID) if (" + abilitySlot + " == 1 and level > 9) then C_PetJournal.SetAbility(" + petSlot + "," + abilitySlot + "," + spellID + ") end if (" + abilitySlot + " == 2 and level > 14) then C_PetJournal.SetAbility(" + petSlot + "," + abilitySlot + "," + spellID + ") end if (" + abilitySlot + " == 3 and level > 19) then C_PetJournal.SetAbility(" + petSlot + "," + abilitySlot + "," + spellID + ") end");
        }



        public string PreParsing(string theLogic)
        {
            theLogic = theLogic.Replace("ISLESSTHAN", "<").Replace("ISGREATERTHAN", ">").Replace("EQUALS", "=").Replace("ISNOT", "<>");
            theLogic = theLogic.Replace("$", "&");
            theLogic = theLogic.Replace("COOLDOWN(SKILL(1))", (!PetCanCast(1)).ToString());
            theLogic = theLogic.Replace("COOLDOWN(SKILL(2))", (!PetCanCast(2)).ToString());
            theLogic = theLogic.Replace("COOLDOWN(SKILL(3))", (!PetCanCast(3)).ToString());
            theLogic = theLogic.Replace("Health(THISPET)", (GetCurrentPetHealth()).ToString());
            theLogic = theLogic.Replace("Health(ENEMYPET)", (GetEnHealth()).ToString());
            theLogic = theLogic.Replace("MyPetLevel", (GetCurrentPetLevel()).ToString());
            theLogic = theLogic.Replace("EnemyPetLevel", (GetCurrentEnemyPetLevel()).ToString());
            theLogic = theLogic.Replace("MyPetsAlive", (GetPetsAlive()).ToString());
            theLogic = theLogic.Replace("EnemyPetsAlive", (GetEnemyPetsAlive()).ToString());
            theLogic = theLogic.Replace("ENEMYSPEED", (GetCurrentEnemySpeed()).ToString());
            theLogic = theLogic.Replace("MYPETSPEED", (GetCurrentSpeed()).ToString());

            theLogic = theLogic.Replace("ENEMYTYPE", (GetCurrentEnemyType()).ToString());
            theLogic = theLogic.Replace("HUMANOID", "1");
            theLogic = theLogic.Replace("DRAGONKIN", "2");
            theLogic = theLogic.Replace("FLYING", "3");
            theLogic = theLogic.Replace("UNDEAD", "4");
            theLogic = theLogic.Replace("CRITTER", "5");
            theLogic = theLogic.Replace("MAGIC", "6");
            theLogic = theLogic.Replace("ELEMENTAL", "7");
            theLogic = theLogic.Replace("BEAST", "8");
            theLogic = theLogic.Replace("AQUATIC", "9");
            theLogic = theLogic.Replace("MECHANICAL", "10");
            theLogic = theLogic.Replace("TURNNUMBER", _BattleRoundNumber.ToString());

            return theLogic;
        }



        public bool ParseLogic(string theLogic)
        {
            string oldlogic = theLogic;

            if (BattleBuddy._MySettings.DetailedLogging) {
                theLogic = theLogic.Replace("ISLESSTHAN", "<");
                theLogic = theLogic.Replace("ISGREATERTHAN", ">");
                theLogic = theLogic.Replace("EQUALS", "=");
                theLogic = theLogic.Replace("ISNOT", "<>");

                theLogic = theLogic.Replace("$", "&");
                oldlogic = theLogic;

                theLogic = theLogic.Replace("COOLDOWN(SKILL(1))", (!PetCanCast(1)).ToString());
                theLogic = theLogic.Replace("COOLDOWN(SKILL(2))", (!PetCanCast(2)).ToString());
                theLogic = theLogic.Replace("COOLDOWN(SKILL(3))", (!PetCanCast(3)).ToString());
                theLogic = theLogic.Replace("Health(THISPET)", (GetCurrentPetHealth()).ToString());
                theLogic = theLogic.Replace("Health(ENEMYPET)", (GetEnHealth()).ToString());
                theLogic = theLogic.Replace("MyPetLevel", (GetCurrentPetLevel()).ToString());
                theLogic = theLogic.Replace("EnemyPetLevel", (GetCurrentEnemyPetLevel()).ToString());
                theLogic = theLogic.Replace("MyPetsAlive", (GetPetsAlive()).ToString());
                theLogic = theLogic.Replace("EnemyPetsAlive", (GetEnemyPetsAlive()).ToString());
                theLogic = theLogic.Replace("ENEMYSPEED", (GetCurrentEnemySpeed()).ToString());
                theLogic = theLogic.Replace("MYPETSPEED", (GetCurrentSpeed()).ToString());
                theLogic = theLogic.Replace("ENEMYTYPE", (GetCurrentEnemyType()).ToString());
                theLogic = theLogic.Replace("HUMANOID", "1");
                theLogic = theLogic.Replace("DRAGONKIN", "2");
                theLogic = theLogic.Replace("FLYING", "3");
                theLogic = theLogic.Replace("UNDEAD", "4");
                theLogic = theLogic.Replace("CRITTER", "5");
                theLogic = theLogic.Replace("MAGIC", "6");
                theLogic = theLogic.Replace("ELEMENTAL", "7");
                theLogic = theLogic.Replace("BEAST", "8");
                theLogic = theLogic.Replace("AQUATIC", "9");
                theLogic = theLogic.Replace("MECHANICAL", "10");
                theLogic = theLogic.Replace("TURNNUMBER", _BattleRoundNumber.ToString());
            }


            theLogic = theLogic.Replace("SWAPOUT", "");
            theLogic = theLogic.Replace("FORFEIT", "");
            theLogic = theLogic.Replace("CASTSPELL(1)", "");
            theLogic = theLogic.Replace("CASTSPELL(2)", "");
            theLogic = theLogic.Replace("CASTSPELL(3)", "");
            theLogic = theLogic.Replace("PASSTURN", "");

            while (theLogic.IndexOf("HASBUFF(") > -1) {
                int FirstChr = theLogic.IndexOf("HASBUFF(") + 8;
                int SecondChr = theLogic.IndexOf(")", FirstChr);
                string dumdumdum = theLogic.Substring(FirstChr, SecondChr - FirstChr);
                theLogic = theLogic.Replace("HASBUFF(" + dumdumdum + ")", (CheckForBuff(dumdumdum)).ToString());
            }

            while (theLogic.IndexOf("WEATHERBUFF(") > -1) {
                int FirstChr = theLogic.IndexOf("WEATHERBUFF(") + 12;
                int SecondChr = theLogic.IndexOf(")", FirstChr);
                string dumdumdum = theLogic.Substring(FirstChr, SecondChr - FirstChr);
                theLogic = theLogic.Replace("WEATHERBUFF(" + dumdumdum + ")", (CheckWeatherBuff(dumdumdum)).ToString());
            }

            while (theLogic.IndexOf("HASENEMYBUFF(") > -1) {
                int FirstChr = theLogic.IndexOf("HASENEMYBUFF(") + 13;
                int SecondChr = theLogic.IndexOf(")", FirstChr);
                string dumdumdum = theLogic.Substring(FirstChr, SecondChr - FirstChr);
                theLogic = theLogic.Replace("HASENEMYBUFF(" + dumdumdum + ")", (CheckEnemyForBuff(dumdumdum)).ToString());
            }

            while (theLogic.IndexOf("HASTEAMBUFF(") > -1) {
                int FirstChr = theLogic.IndexOf("HASTEAMBUFF(") + 12;
                int SecondChr = theLogic.IndexOf(")", FirstChr);
                string dumdumdum = theLogic.Substring(FirstChr, SecondChr - FirstChr);
                theLogic = theLogic.Replace("HASTEAMBUFF(" + dumdumdum + ")", (CheckTeamBuff(dumdumdum, 1)).ToString());
            } //HASTEAMBUFF ENEMYTEAMBUFF

            while (theLogic.IndexOf("ENEMYTEAMBUFF(") > -1) {
                int FirstChr = theLogic.IndexOf("ENEMYTEAMBUFF(") + 14;
                int SecondChr = theLogic.IndexOf(")", FirstChr);
                string dumdumdum = theLogic.Substring(FirstChr, SecondChr - FirstChr);
                theLogic = theLogic.Replace("ENEMYTEAMBUFF(" + dumdumdum + ")", (CheckTeamBuff(dumdumdum, 2)).ToString());
            }

            bool dumdum = Calc(theLogic);
            BBLog.LogTrace("----------------------------------------------------------------");
            BBLog.LogTrace("Following logic returned " + dumdum);
            BBLog.LogTrace("Logic " + oldlogic);

            return dumdum;
        }



        public int BattleRating(int petLevel, int petHP, string petID, int enemytype, int enemylevel)
        {
            int advantage = 0;
            int disadvantage = 0;
            int rating = 0;

            int mypet = GetTypeByID(petID);
            if (mypet == DumbChoiceTakeMoreDMG(enemytype)) disadvantage = -2;
            if (mypet == DumbChoiceDealLessDMG(enemytype)) disadvantage = disadvantage - 1;//rating -1;
            if (mypet == SmartChoiceTakeLessDMG(enemytype)) advantage = 1;
            if (mypet == SmartChoiceDealMoreDMG(enemytype)) advantage = advantage + 2;

            /*****************************************/

            string s = "1 + 1 * 3";

            var value = Calculate(s);
            var total = 0;

            s = _MySettings.HPFormula;
            s = s.Replace("petHP", petHP.ToString()).Replace("HPFactor", BattleBuddy._MySettings.HPFactor.ToString());

            var HPresult = Calculate(s);
            total = int.Parse(HPresult.ToString());

            s = _MySettings.AdFormula;
            s = s.Replace("advantage", advantage.ToString()).Replace("AdFactor", _MySettings.AdFactor.ToString());

            var Adresult = Calculate(s);
            total = total + int.Parse(Adresult.ToString());


            s = _MySettings.DisFormula;
            s = s.Replace("disadvantage", disadvantage.ToString()).Replace("DisFactor", _MySettings.DisFactor.ToString());

            var Disresult = Calculate(s);
            total = total + int.Parse(Disresult.ToString());

            s = _MySettings.LevelFormula;
            s = s.Replace("petLevel", petLevel.ToString()).Replace("enemylevel", enemylevel.ToString()).Replace("LevelFactor", _MySettings.LevelFactor.ToString());

            var Levelresult = Calculate(s);
            total = total + int.Parse(Levelresult.ToString());


            /***************************************/

            //do more rating stuff with health percentages, level difference
            rating = total; /*(petHP * BattleBuddy.MySettings.HPFactor) +
                     (advantage * 50 * BattleBuddy.MySettings.AdFactor) +
                     (disadvantage * 50 * BattleBuddy.MySettings.DisFactor) +
                     ((petLevel - enemylevel) * 4 * BattleBuddy.MySettings.LevelFactor);*/
            int oldrating = rating;
            if (petHP < 30) rating = rating - 10000;
            if (petHP < 15) rating = rating - 40000;
            if (petHP < 5) rating = rating - 50000;
            if (!CanSummon(petID)) rating = -100000000;

            if (BattleBuddy._MySettings.DetailedLogging) {
                BBLog.Log("~~~~~~~~~~~~~~~~~~~~~Rating info~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
                BBLog.Log("HP            " + petHP.ToString("000") + " x " + BattleBuddy._MySettings.HPFactor + " = " + HPresult.ToString());
                BBLog.Log("Advantage     " + advantage.ToString("000") + " x " + BattleBuddy._MySettings.AdFactor + " = " + Adresult.ToString());
                BBLog.Log("Disadvantage  " + disadvantage.ToString("000") + " x " + BattleBuddy._MySettings.DisFactor + " = " + Disresult.ToString());
                BBLog.Log("Level  " + (petLevel - enemylevel).ToString("00") + " x 4 x " + BattleBuddy._MySettings.LevelFactor + " = " + Levelresult.ToString());
                BBLog.Log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
                BBLog.Log("Total Rating : " + oldrating + "      ");
                BBLog.Log("Final Rating : " + rating + "    (after extreme low HP penalty)  ");
                BBLog.Log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            }
            return rating;
        }



        public bool InPetCombat()
        {
            List<string> cnt = Lua.GetReturnValues("if (C_PetBattles.IsInBattle() == true) then return 1 end return 0");

            if (cnt != null) { if (cnt[0] != "0") return true; }
            return false;
        }


        public bool CanSelect(int petnum)
        {
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.CanPetSwapIn(" + petnum + ")");

            if (cnt != null) { if (cnt[0] == "1") return true; }
            return false;
        }



        public bool MustSelectNew()
        {
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.ShouldShowPetSelect()");

            if (cnt != null) { if (cnt[0] == "1") return true; }
            return false;
        }


        public bool CanTrap()
        {
            List<string> cnt = Lua.GetReturnValues("dummy,reason=C_PetBattles.IsTrapAvailable() return dummy,reason");

            if (cnt != null) { if (cnt[0] == "1") return true; }
            return false;
        }


        public bool CanSummon(string petID)
        {
            List<string> cnt = Lua.GetReturnValues("return C_PetJournal.PetIsSummonable(" + petID + ");");

            if (cnt != null) { if (cnt[0] == "1") return true; }
            return false;
        }



        public bool PetCanCast(int skillnum)
        {
            List<string> cnt = Lua.GetReturnValues("local isUsable, currentCooldown = C_PetBattles.GetAbilityState(LE_BATTLE_PET_ALLY, C_PetBattles.GetActivePet(LE_BATTLE_PET_ALLY), " + skillnum + "); if isUsable == nil then isUsable=0 end return isUsable,currentCooldown");

            if (cnt != null) { if (cnt[0] == "1") return true; }
            return false;
        }


        public bool CanFight()
        {
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.IsWaitingOnOpponent()");

            if (cnt != null) { if (cnt[0] == "0") return true; }
            return false;
        }



        public bool CanCastSomething()
        {
            List<string> cnt = Lua.GetReturnValues("isUsable, currentCooldown = C_PetBattles.GetAbilityState(1, C_PetBattles.GetActivePet(1), 1) if (isUsable ~= true) then isUsable, currentCooldown = C_PetBattles.GetAbilityState(1, C_PetBattles.GetActivePet(1), 2) if (isUsable ~= true) then isUsable, currentCooldown = C_PetBattles.GetAbilityState(1, C_PetBattles.GetActivePet(1), 3) if (isUsable ~= true) then if (C_PetBattles.CanActivePetSwapOut() ~= true) then return false end end end end return true");

            if (cnt != null) { if (cnt[0] == "1") return true; }
            return false;
        }


        public static string ReadSlot(int slotnr)
        {
            List<string> cnt = Lua.GetReturnValues("dummy={} for i = 1, 3   do  local petID= C_PetJournal.GetPetLoadOutInfo(i); dummy[i]=petID  end return tonumber(dummy[1],16),tonumber(dummy[2],16),tonumber(dummy[3],16);");
            BBLog.LogTrace("Slot has ID : " + cnt[slotnr - 1]);
            return cnt[slotnr - 1];
        }



        public static string ReadIndex(int slotnr)
        {
            List<string> cnt = Lua.GetReturnValues("local petID,_ = C_PetJournal.GetPetInfoByIndex(" + slotnr.ToString() + ") return tonumber(petID,16)");

            return cnt[0];
        }



        public static string ReadIndexSpecies(int slotnr)
        {
            List<string> cnt = Lua.GetReturnValues("local _,speciesID = C_PetJournal.GetPetInfoByIndex(" + slotnr.ToString() + ") return speciesID");

            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == cnt[0]) return allpetz[i + 1];
            }
            return "";
        }



        public static string IndexIcon(int index)
        {
            List<string> cnt = Lua.GetReturnValues("local petID, speciesID = C_PetJournal.GetPetInfoByIndex(" + index + "); return speciesID");

            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == cnt[0]) return allpetz[i + 2];
            }
            return "";
        }



        public string ReadActiveSlot()
        {
            List<string> cnt1 = Lua.GetReturnValues("return C_PetBattles.GetActivePet(1)");
            int activepet = _FixedIndex[Int32.Parse(cnt1[0])];
            List<string> cnt = Lua.GetReturnValues("dummy={} for i = 1, 3  do  local petID= C_PetJournal.GetPetLoadOutInfo(i); dummy[i]=petID  end return tonumber(dummy[" + activepet + "],16);");
            return cnt[0];//decAgain.ToString();
        }



        public string ReadActiveSlotSpecies()
        {
            List<string> cnt = Lua.GetReturnValues("return C_PetBattles.GetPetSpeciesID(1,C_PetBattles.GetActivePet(1))");
            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == cnt[0]) return allpetz[i + 1];
            }
            return "";
        }



        public static string ReadSlotSpecies(int slotnum)
        {
            List<string> cnt = Lua.GetReturnValues("local petID = C_PetJournal.GetPetLoadOutInfo(" + slotnum + "); local speciesID = C_PetJournal.GetPetInfoByPetID(petID) return speciesID");
            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == cnt[0]) return allpetz[i + 1];
            }
            return "";
        }


        public string ActiveSlotIcon()
        {
            List<string> cnt = Lua.GetReturnValues("local petID = C_PetJournal.GetPetLoadOutInfo(C_PetBattles.GetActivePet(1)); local speciesID = C_PetJournal.GetPetInfoByPetID(petID) return speciesID");
            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == cnt[0]) return allpetz[i + 2];
            }
            return "";
        }

        public static string SlotIcon(int slotnr)
        {
            List<string> cnt = Lua.GetReturnValues("local petID = C_PetJournal.GetPetLoadOutInfo(" + slotnr + "); local speciesID = C_PetJournal.GetPetInfoByPetID(petID) return speciesID");
            BBLog.LogTrace("PetId: " +cnt[0]);
            //int decAgain = int.Parse(, System.Globalization.NumberStyles.HexNumber);
            //return cnt[0];//decAgain.ToString();
            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == cnt[0]) return allpetz[i + 2];
            }
            return "";
        }



        public static int SmartChoiceTakeLessDMG(int enemytype)
        {
            if (enemytype > 10 || enemytype < 0) enemytype = 1;
            int[] smart = new int[] { 0, 8, 4, 2, 9, 1, 10, 5, 3, 6, 7 };
            return smart[enemytype];
        }



        public static int SmartChoiceDealMoreDMG(int enemytype)
        {
            if (enemytype > 10 || enemytype < 0) enemytype = 1;
            int[] smart = new int[] { 0, 4, 1, 6, 5, 8, 2, 9, 10, 3, 7 };
            return smart[enemytype];
        }



        public static int DumbChoiceDealLessDMG(int enemytype)
        {
            if (enemytype > 10 || enemytype < 0) enemytype = 1;
            int[] smart = new int[] { 0, 5, 3, 8, 2, 7, 9, 10, 1, 4, 6 };
            return smart[enemytype];
        }



        public static int DumbChoiceTakeMoreDMG(int enemytype)
        {
            if (enemytype > 10 || enemytype < 0) enemytype = 1;
            int[] smart = new int[] { 0, 2, 6, 9, 1, 4, 3, 10, 5, 7, 8 };
            return smart[enemytype];
        }


        public bool CheckWeatherBuff(string buffnum)
        {
            List<string> cnt = Lua.GetReturnValues("for i=1, C_PetBattles.GetNumAuras(0,0) do local auraID = C_PetBattles.GetAuraInfo(LE_BATTLE_PET_WEATHER, PET_BATTLE_PAD_INDEX, i) if (auraID == " + buffnum + ") then return true end end return false");
            return (cnt != null && cnt.Count > 0 && cnt[0] == "1");
        }



        public bool CheckTeamBuff(string buffnum, int teamnum)
        {
            List<string> cnt = Lua.GetReturnValues("for i=1, C_PetBattles.GetNumAuras(" + teamnum + ",0) do local auraID = C_PetBattles.GetAuraInfo(" + teamnum + ", PET_BATTLE_PAD_INDEX, i) if (auraID == " + buffnum + ") then return true end end return false");
            return (cnt != null && cnt.Count > 0 && cnt[0] == "1");
        }



        public bool CheckForBuff(string buffnum)
        {
            List<string> cnt = Lua.GetReturnValues("for j=1,C_PetBattles.GetNumAuras(1,C_PetBattles.GetActivePet(1)) do  local buffid = C_PetBattles.GetAuraInfo(1,C_PetBattles.GetActivePet(1),j)  if buffid == " + buffnum + " then return (true) end end return( false) ");
            return ((cnt != null && cnt.Count > 0 && cnt[0] == "1")
                    || (CheckTeamBuff(buffnum, 1))
                    || (CheckWeatherBuff(buffnum))
                    );
        }



        public bool CheckEnemyForBuff(string buffnum)
        {
            List<string> cnt = Lua.GetReturnValues("for j=1,C_PetBattles.GetNumAuras(2,C_PetBattles.GetActivePet(2)) do  local buffid = C_PetBattles.GetAuraInfo(2,C_PetBattles.GetActivePet(2),j)  if buffid == " + buffnum + " then return (true) end end return( false) ");
            return ((cnt != null && cnt.Count > 0 && cnt[0] == "1")
                    || (CheckTeamBuff(buffnum, 2))
                    || (CheckWeatherBuff(buffnum))
                    );
        }



        public int GetTypeByName(string petname)
        {
            Lua.DoString("C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_FAVORITES, false) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_COLLECTED, true) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_NOT_COLLECTED, true) ");
            Lua.DoString("C_PetJournal.ClearSearchFilter() C_PetJournal.AddAllPetSourcesFilter() C_PetJournal.AddAllPetTypesFilter() ");
            petname = GetSpeciesByName(petname);
            List<string> cnt = Lua.GetReturnValues("local dummy=-1 for i=1,C_PetJournal.GetNumPets(false) do     local petID, speciesID, isOwned, customName, level, favorite, isRevoked, name, icon, petType  = C_PetJournal.GetPetInfoByIndex(i, false)  if speciesID == " + petname + " then dummy=petType ; end end return dummy;");

            if (cnt[0] != null && cnt[0] != "-1") {
                int numValue = -1;
                try {
                    numValue = int.Parse(cnt[0]);
                } catch (Exception exc) {
                    BBLog.LogException(exc);
                }
                return numValue;
            }
            return -1;
        }



        public int GetRarityBySpeciesID(string speciesid)
        {
            Lua.DoString("C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_FAVORITES, false) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_COLLECTED, true) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_NOT_COLLECTED, true) ");
            Lua.DoString("C_PetJournal.ClearSearchFilter() C_PetJournal.AddAllPetSourcesFilter() C_PetJournal.AddAllPetTypesFilter() ");
            ////Lua.DoString("C_PetJournal.SetSearchFilter('" + petname + "')");

            string lustring = "local dummy=-1 for i=1,C_PetJournal.GetNumPets(false) do     local petID, speciesID, isOwned, customName, level, favorite, isRevoked, name, icon, petType  = C_PetJournal.GetPetInfoByIndex(i, false)  if isOwned then local _, _, _, _, rarity = C_PetJournal.GetPetStats(petID) if (speciesID == " + speciesid + ")then if (rarity > dummy) then dummy=rarity ; end end end end return dummy;";

            List<string> cnt = Lua.GetReturnValues(lustring);

            if (cnt[0] != null && cnt[0] != "-1") {

                int numValue = -1;
                try {
                    numValue = int.Parse(cnt[0]);
                } catch (Exception exc) {
                    BBLog.LogException(exc);
                }
                return numValue;
            }
            return -1;
        }



        public int GetRarityByName(string petname)
        {
            Lua.DoString("C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_FAVORITES, false) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_COLLECTED, true) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_NOT_COLLECTED, true) ");
            Lua.DoString("C_PetJournal.ClearSearchFilter() C_PetJournal.AddAllPetSourcesFilter() C_PetJournal.AddAllPetTypesFilter() ");
            petname = GetSpeciesByName(petname);
            string lustring = "local dummy=-1 for i=1,C_PetJournal.GetNumPets(false) do     local petID, speciesID, isOwned, customName, level, favorite, isRevoked, name, icon, petType  = C_PetJournal.GetPetInfoByIndex(i, false)  if isOwned then local _, _, _, _, rarity = C_PetJournal.GetPetStats(petID) if (speciesID == " + petname + ")then if (rarity > dummy) then dummy=rarity ; end end end end return dummy;";

            List<string> cnt = Lua.GetReturnValues(lustring);

            if (cnt[0] != null && cnt[0] != "-1") {
                int numValue = -1;
                try {
                    numValue = int.Parse(cnt[0]);
                } catch (Exception exc) {
                    BBLog.LogException(exc);
                }
                return numValue;
            }
            return -1;

        }



        public static int GetTypeByID(string thepetID)
        {
            Lua.DoString("C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_FAVORITES, false) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_COLLECTED, true) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_NOT_COLLECTED, true) ");
            Lua.DoString("C_PetJournal.ClearSearchFilter() C_PetJournal.AddAllPetSourcesFilter() C_PetJournal.AddAllPetTypesFilter() ");
            ////Lua.DoString("C_PetJournal.SetSearchFilter('" + petname + "')");

            List<string> cnt = Lua.GetReturnValues("local dummy=-1 for i=1,C_PetJournal.GetNumPets(false) do     local petID, speciesID, isOwned, customName, level, favorite, isRevoked, name, icon, petType  = C_PetJournal.GetPetInfoByIndex(i, false) if tonumber(petID,16) == " + thepetID + " then return petType end end  print('finished') return dummy;");
            BBLog.LogTrace("Type by Id returned : " + cnt[0]);
            if (cnt != null) {
                if (cnt[0] != null && cnt[0] != "-1") {
                    int numValue = -1;
                    try {
                        numValue = int.Parse(cnt[0]);
                    } catch (Exception exc) {
                        BBLog.LogException(exc);
                    }
                    return numValue;
                }
            }
            return -1;
        }



        public static string GetNameByID(string thepetID)
        {
            Lua.DoString("C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_FAVORITES, false) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_COLLECTED, true) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_NOT_COLLECTED, true) ");
            Lua.DoString("C_PetJournal.ClearSearchFilter() C_PetJournal.AddAllPetSourcesFilter() C_PetJournal.AddAllPetTypesFilter() ");
            ////Lua.DoString("C_PetJournal.SetSearchFilter('" + petname + "')");

            List<string> cnt = Lua.GetReturnValues("local dummy='' for i=1,C_PetJournal.GetNumPets(false) do     local petID, speciesID, isOwned, customName, level, favorite, isRevoked, name, icon, petType  = C_PetJournal.GetPetInfoByIndex(i, false)  if tonumber(petID,16) == " + thepetID + " then dummy=name ; end end return dummy;");

            if (cnt[0] != null && cnt[0] != "") {
                return cnt[0];
            }
            return "Error";
        }



        public static string GetSpeciesIDByID(string thepetID)
        {
            Lua.DoString("C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_FAVORITES, false) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_COLLECTED, true) C_PetJournal.SetFlagFilter(LE_PET_JOURNAL_FLAG_NOT_COLLECTED, true) ");
            Lua.DoString("C_PetJournal.ClearSearchFilter() C_PetJournal.AddAllPetSourcesFilter() C_PetJournal.AddAllPetTypesFilter() ");
            ////Lua.DoString("C_PetJournal.SetSearchFilter('" + petname + "')");

            List<string> cnt = Lua.GetReturnValues("local dummy='' for i=1,C_PetJournal.GetNumPets(false) do local petID, speciesID, isOwned, customName, level, favorite, isRevoked, name, icon, petType  = C_PetJournal.GetPetInfoByIndex(i, false)  if petID ~= nil then if tonumber(petID,16) == " + thepetID + " then dummy=tostring(speciesID) ; end end end return dummy;");

            if (cnt[0] != null && cnt[0] != "") {
                return cnt[0];
            }
            return "Error";
        }



        public static string GetNameBySpeciesID(string speciesID)
        {
            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == speciesID) return allpetz[i + 1];

            }
            return "Error";
        }



        public static string GetSpeciesByName(string speciesID)
        {
            for (int i = 0; i < allpetz.Length; i++) {
                if (allpetz[i] == speciesID) return allpetz[i - 1];

            }
            return "Error";
        }


        public static WoWUnit WildBattleTarget()
        {

            WoWUnit ret = (from unit in ObjectManager.GetObjectsOfType<WoWUnit>(true, true)
                           orderby unit.Distance ascending

                           where !Blacklist.Contains(unit.Guid)
                           //where unit.CreatureType.ToString() == "14"
                           where unit.IsPetBattleCritter
                           where !unit.IsDead
                           where (_MySettings.UseWhiteList && _TheWhitelist.Contains(unit.Name.ToLower()) || !_MySettings.UseWhiteList)
                           where (_MySettings.UseBlackList && !_TheBlacklist.Contains(unit.Name.ToLower()) || !_MySettings.UseBlackList)
                           where unit.Distance2D < BattleBuddy._MySettings.Distance
                           select unit).FirstOrDefault();

            if (ret != null) {
                ret.Target();
                int dumlevel = GetWildLevel();
                if (dumlevel > GetLowLevel() - (BattleBuddy._MySettings.BelowLevel + 1) && dumlevel < GetHighLevel() + BattleBuddy._MySettings.AboveLevel + 1) {
                    return ret;
                } else {
                    if (dumlevel > 0) {
                        BBLog.Log("Blacklisted target because level is " + dumlevel + ", the min is " + (GetLowLevel() - (BattleBuddy._MySettings.BelowLevel + 1)) + " and the max is " + (GetHighLevel() + BattleBuddy._MySettings.AboveLevel + 1));
                        Blacklist.Add(ret.Guid, TimeSpan.FromMinutes(1));
                    }
                }
            }
            return null;
        }



        public static int GetLowLevel()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("local dummy = 99 for j=1,3 do local petID= C_PetJournal.GetPetLoadOutInfo(j) local speciesID, customName, level = C_PetJournal.GetPetInfoByPetID(petID) if level < dummy then dummy=level end end return dummy");
            try {
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public static int GetPetsAlive()
        {
            int getal = 0;

            List<string> cnt = Lua.GetReturnValues("dummy=0 for i = 1,C_PetBattles.GetNumPets(1)    do health, maxhealth = C_PetBattles.GetHealth(1, i) if health > 0 then dummy=dummy+1 end end return dummy");
            try {
                BBLog.LogTrace("Number pets alive: "+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public static int GetEnemyPetsAlive()
        {
            int getal = 0;

            List<string> cnt = Lua.GetReturnValues("dummy=0 for i = 1,C_PetBattles.GetNumPets(2)    do health, maxhealth = C_PetBattles.GetHealth(2, i) if health > 0 then dummy=dummy+1 end end return dummy");
            try {
                BBLog.LogTrace("Number Enemy pets alive: "+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }



        public static int GetHighLevel()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("local dummy = 0 for j=1,3 do local petID= C_PetJournal.GetPetLoadOutInfo(j) local speciesID, customName, level = C_PetJournal.GetPetInfoByPetID(petID) if level > dummy then dummy=level end end return dummy");
            try {
                BBLog.LogTrace("My pets highest level: "+cnt[0]);
                getal = int.Parse(cnt[0]);
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }

        public static int GetWildLevel()
        {
            int getal = 0;
            List<string> cnt = Lua.GetReturnValues("return UnitBattlePetLevel('target')");
            try {
                if (cnt.Count > 0) {
                    BBLog.LogTrace("Wild pet level: " + cnt[0]);
                    getal = int.Parse(cnt[0]);
                } 
            } catch (Exception exc) {
                BBLog.LogException(exc);
            }
            return getal;
        }
    }
}



//***********************************************************
//   Settings part!!                             *
//***********************************************************
namespace BattleBuddyplug
{
    // credits to Apoc for showing how to use the HB settings. & also credits from me, the guy that stole this from the AutoAngler Addon
    //DefaultLogic[0]={0,32000,""};


    public class BBSettings : Settings
    {

        public BBSettings(string settingsPath)
            : base(settingsPath)
        {
            Load();
        }

        [Setting, Styx.Helpers.DefaultValue(4)]
        public int HPFactor { get; set; }

        [Setting, Styx.Helpers.DefaultValue(-30)]
        public int LevelFactor { get; set; }

        [Setting, Styx.Helpers.DefaultValue(1)]
        public int AdFactor { get; set; }

        [Setting, Styx.Helpers.DefaultValue(1)]
        public int DisFactor { get; set; }

        [Setting, Styx.Helpers.DefaultValue(300)]
        public int Distance { get; set; }

        [Setting, Styx.Helpers.DefaultValue(3)]
        public int GetRarity { get; set; }

        [Setting, Styx.Helpers.DefaultValue(5)]
        public int BlacklistCounterLimit { get; set; }

        [Setting, Styx.Helpers.DefaultValue(5)]
        public int SkipCounterLimit { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool DoPVP { get; set; }

        [Setting, Styx.Helpers.DefaultValue(5)]
        public int PVPMinTime { get; set; }

        [Setting, Styx.Helpers.DefaultValue(10)]
        public int PVPMaxTime { get; set; }

        [Setting, Styx.Helpers.DefaultValue(1)]
        public int MinPetsAlive { get; set; }

        [Setting, Styx.Helpers.DefaultValue(3)]
        public int BelowLevel { get; set; }

        [Setting, Styx.Helpers.DefaultValue(3)]
        public int AboveLevel { get; set; }

        [Setting, Styx.Helpers.DefaultValue(0)]
        public int UseBandagesToHeal { get; set; }

        [Setting, Styx.Helpers.DefaultValue(1)]
        public int UseHealSkill { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool ForfeitIfNotInteresting { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool UseWhiteList { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool UseBlackList { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool UseRatingSystem { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool DoPreCombatSwapping { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool CheckAllowUsageTracking { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool AllowAutoUpdate { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool AllowRoleDetect { get; set; }

        [Setting, Styx.Helpers.DefaultValue("0.150")]
        public string CurrentRevision { get; set; }

        [Setting, Styx.Helpers.DefaultValue("")]
        public string LastDayChecked { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool BPSEnabled { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool DetailedLogging { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool AmHorde { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool Slot1SwapEnabled { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool Slot1SwapFavoriteOnly { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool Slot1TradeableOnly { get; set; }

        [Setting, Styx.Helpers.DefaultValue(true)]
        public bool Slot1AllowWild { get; set; }

        [Setting, Styx.Helpers.DefaultValue(1)]
        public int Slot1SwapMinLevel { get; set; }

        [Setting, Styx.Helpers.DefaultValue(20)]
        public int Slot1SwapMaxLevel { get; set; }

        [Setting, Styx.Helpers.DefaultValue("petHP * HPFactor")]
        public string HPFormula { get; set; }

        [Setting, Styx.Helpers.DefaultValue("advantage * 50 * AdFactor")]
        public string AdFormula { get; set; }

        [Setting, Styx.Helpers.DefaultValue("disadvantage * 50 * DisFactor")]
        public string DisFormula { get; set; }

        [Setting, Styx.Helpers.DefaultValue("(petLevel - enemylevel) * 4 * LevelFactor")]
        public string LevelFormula { get; set; }

        [Setting, Styx.Helpers.DefaultValue("2,3,1")]
        public string PetOrder { get; set; }

        [Setting, Styx.Helpers.DefaultValue(false)]
        public bool IBSupport { get; set; }

        public void PrintSettings()
        {
            BBLog.Log("**************************************************************************************");
            BBLog.Log("Settings :");
            //Settings set = MySettings;
            foreach (var kvp in GetSettings()) {
                BBLog.Log(String.Format("  {0}: {1}", kvp.Key, kvp.Value.ToString()));
            }
        }
    }



    public class PetBattleSettings : Settings
    {

        public PetBattleSettings(string settingsPath)
            : base(settingsPath)
        {
            Load();
        }

        [Setting, Styx.Helpers.DefaultValue("SWAPOUT Health(THISPET) ISLESSTHAN 30@CASTSPELL(1) COOLDOWN(SKILL(1)) EQUALS false")]
        public string Logic { get; set; }

        [Setting, Styx.Helpers.DefaultValue("ASSIGNABILITY1(0)@ASSIGNABILITY2(0)@ASSIGNABILITY3(0)")]
        public string SpellLayout { get; set; }
    }

}

